<template>
  <div ref="$outerWrapper" class="bai-split-wrapper">
    <div :style="{height: `${topHeight}px`}" class="top-pane">
      <slot name="top"></slot>
    </div>
    <div ref="$trigger" class="trigger" @mousedown="handleMousedown">
      <slot name="trigger">
        <Trigger mode="vertical"></Trigger>
      </slot>
    </div>
    <div :style="{height: `${bottomHeight}px`}" class="bottom-pane">
      <slot name="bottom"/>
    </div>
  </div>
</template>

<script>
// 普通 <script>, 在模块范围下执行(只执行一次)
// 声明额外的选项
export default {
  name: 'Vertical',
}
</script>

<script setup>
import {defineProps, defineEmits, ref, computed, nextTick, watch, onMounted, onUnmounted} from 'vue'
import Trigger from './Trigger'

const props = defineProps({
  divValue: { // 上半部分的大小，数字类型为百分比，以px为结尾的代表像素值
    type: [Number, String],
    default: 0.5
  },
  topMin: { // 上半部分的大小最小值，数字类型为百分比，以px为结尾的代表像素值
    type: [Number, String],
    default: '40px'
  },
  bottomMin: { // 下半部分的大小最小值，数字类型为百分比，以px为结尾的代表像素值
    type: [Number, String],
    default: '40px'
  }
})
const emits = defineEmits([
  'update:divValue',
  'onMoving',
  'onMoveEnd',
  'onMoveStart'
])
/**
 * Events
 * @on-move-start
 * @on-moving 返回值：事件对象，但是在事件对象中加入了两个参数：atMin(当前是否在最小值处), atMax(当前是否在最大值处)
 * @on-move-end
 */
// -----基本参数初始化部分------
const $outerWrapper = ref(null)
const $trigger = ref(null)
const topHeight = ref(0)  // 上部分高度，单位为像素
const bottomHeight = ref(0)  // 下部分高度，单位为像素
let restHeight = 0  // 去除分割线后剩余高度，单位为像素
let computedTopMin = 0  // 上部分最小高度，单位为像素
let computedBottomMin = 0  // 下部分最小高度，单位为像素
const divValueIsPx = computed(() => typeof props.divValue === 'string')
const getComputedThresholdValue = type => {
  // 返回阈值的像素大小
  return typeof props[type] === 'string' ? parseFloat(props[type]) : restHeight * props[type]
}
const divValue = computed(() => props.divValue)
const computeOffset = () => {
  nextTick(() => {
    const outerHeight = $outerWrapper.value['offsetHeight'] // 最外边框高度，单位为像素
    const triggerHeight = $trigger.value['offsetHeight'] // 分割线高度，单位为像素
    restHeight = outerHeight - triggerHeight
    computedTopMin = getComputedThresholdValue('topMin');
    computedBottomMin = getComputedThresholdValue('bottomMin');
    topHeight.value = divValueIsPx.value ? parseFloat(props.divValue) : restHeight * props.divValue
    bottomHeight.value = restHeight - topHeight.value
  })
}
watch(divValue, () => {
  computeOffset();
})
onMounted(() => {
  computeOffset()
  window.addEventListener('resize', computeOffset)
})
onUnmounted(() => {
  window.removeEventListener('resize', computeOffset)
})

// ------鼠标移动处理------
let initAxisY = 0 // 鼠标点击时Y轴位置，单位为像素
let oldDivValue = 0 // 鼠标点击时，divValue的备份
let oldTopHeight = 0 // 鼠标点击时，topHeight的备份
// eslint-disable-next-line no-unused-vars
let isMoving = false

const getAnotherHeight = value => {
  return restHeight - value
}
const handleMove = (e) => {
  let pageOffset = e.pageY
  let offset = pageOffset - initAxisY
  let newTopHeight = divValueIsPx.value ? oldTopHeight + offset : restHeight * parseFloat(oldDivValue) + offset
  let newBottomHeight = getAnotherHeight(newTopHeight)
  if (newTopHeight <= computedTopMin) {
    newTopHeight = computedTopMin
    newBottomHeight = getAnotherHeight(newTopHeight)
    e.atTop = true
  } else {
    e.atTop = false
  }
  if (newBottomHeight <= computedBottomMin) {
    newBottomHeight = computedBottomMin
    newTopHeight = getAnotherHeight(newBottomHeight)
    e.atBottom = true
  } else {
    e.atBottom = false
  }
  if (divValueIsPx.value) {
    emits('update:divValue', `${newTopHeight}px`)
  } else {
    emits('update:divValue', newTopHeight / restHeight)
  }
  emits('onMoving', e)
}
const handleMousedown = (e) => {
  initAxisY = e.pageY
  oldDivValue = props.divValue
  oldTopHeight = topHeight.value
  isMoving = true
  document.addEventListener('mousemove', handleMove)
  document.addEventListener('mouseup', handleUp)
  emits('onMoveStart')
}
const handleUp = () => {
  isMoving = false
  document.removeEventListener('mousemove', handleMove)
  document.removeEventListener('mouseup', handleUp)
  emits('onMoveEnd')
}
</script>

<style scoped lang="sass">
  .bai-split-wrapper
    display: flex
    flex-direction: column

    .trigger
      user-select: none
</style>
